"""
企业级金融数据MCP服务系统 - 新闻数据模型
提供完整的新闻相关数据SQLAlchemy ORM模型定义
"""

from datetime import datetime, date
from decimal import Decimal
from typing import Optional, Dict, Any, List
from sqlalchemy import String, DateTime, Date, Boolean, Integer, Numeric, Text, Index, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.dialects.postgresql import JSONB, ARRAY

from .base import BaseFinancialModel, DataVersionMixin, SyncStatusMixin, PartitionMixin


class NewsArticle(BaseFinancialModel, PartitionMixin):
    """
    新闻文章模型
    存储金融新闻文章的基本信息和内容
    """
    __tablename__ = "news_article"
    
    # 新闻ID
    news_id: Mapped[str] = mapped_column(String(100), primary_key=True, comment="新闻ID")
    
    # 标题
    title: Mapped[str] = mapped_column(String(500), nullable=False, comment="标题")
    
    # 副标题
    subtitle: Mapped[Optional[str]] = mapped_column(String(500), nullable=True, comment="副标题")
    
    # 摘要
    summary: Mapped[Optional[str]] = mapped_column(Text, nullable=True, comment="摘要")
    
    # 正文内容
    content: Mapped[Optional[str]] = mapped_column(Text, nullable=True, comment="正文内容")
    
    # 作者
    author: Mapped[Optional[str]] = mapped_column(String(200), nullable=True, comment="作者")
    
    # 来源
    source: Mapped[str] = mapped_column(String(200), nullable=False, comment="来源")
    
    # 发布时间
    publish_time: Mapped[datetime] = mapped_column(DateTime, nullable=False, comment="发布时间")
    
    # 更新时间
    update_time: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True, comment="更新时间")
    
    # 新闻分类：宏观, 股市, 债市, 汇市, 商品, 公司, 行业等
    category: Mapped[str] = mapped_column(String(50), nullable=False, comment="新闻分类")
    
    # 子分类
    subcategory: Mapped[Optional[str]] = mapped_column(String(50), nullable=True, comment="子分类")
    
    # 重要程度：1-5级，5为最重要
    importance_level: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="重要程度")
    
    # 情感倾向：正面, 负面, 中性
    sentiment: Mapped[Optional[str]] = mapped_column(String(20), nullable=True, comment="情感倾向")
    
    # 情感得分：-1到1之间
    sentiment_score: Mapped[Optional[Decimal]] = mapped_column(Numeric(5, 4), nullable=True, comment="情感得分")
    
    # 关键词
    keywords: Mapped[Optional[List[str]]] = mapped_column(ARRAY(String), nullable=True, comment="关键词")
    
    # 相关股票代码
    related_stocks: Mapped[Optional[List[str]]] = mapped_column(ARRAY(String), nullable=True, comment="相关股票代码")
    
    # 相关行业代码
    related_industries: Mapped[Optional[List[str]]] = mapped_column(ARRAY(String), nullable=True, comment="相关行业代码")
    
    # 相关概念
    related_concepts: Mapped[Optional[List[str]]] = mapped_column(ARRAY(String), nullable=True, comment="相关概念")
    
    # 原文链接
    url: Mapped[Optional[str]] = mapped_column(String(1000), nullable=True, comment="原文链接")
    
    # 图片链接
    image_urls: Mapped[Optional[List[str]]] = mapped_column(ARRAY(String), nullable=True, comment="图片链接")
    
    # 阅读量
    view_count: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="阅读量")
    
    # 点赞数
    like_count: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="点赞数")
    
    # 评论数
    comment_count: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="评论数")
    
    # 转发数
    share_count: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="转发数")
    
    # 是否置顶
    is_top: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, comment="是否置顶")
    
    # 是否热点
    is_hot: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, comment="是否热点")
    
    # 语言
    language: Mapped[str] = mapped_column(String(10), nullable=False, default="zh", comment="语言")
    
    # 地区
    region: Mapped[Optional[str]] = mapped_column(String(50), nullable=True, comment="地区")
    
    # 扩展信息
    extra_info: Mapped[Optional[Dict[str, Any]]] = mapped_column(JSONB, nullable=True, comment="扩展信息")
    
    __table_args__ = (
        Index('idx_news_article_title', 'title'),
        Index('idx_news_article_source', 'source'),
        Index('idx_news_article_publish_time', 'publish_time'),
        Index('idx_news_article_category', 'category'),
        Index('idx_news_article_subcategory', 'subcategory'),
        Index('idx_news_article_importance', 'importance_level'),
        Index('idx_news_article_sentiment', 'sentiment'),
        Index('idx_news_article_keywords', 'keywords', postgresql_using='gin'),
        Index('idx_news_article_related_stocks', 'related_stocks', postgresql_using='gin'),
        Index('idx_news_article_related_industries', 'related_industries', postgresql_using='gin'),
        Index('idx_news_article_is_top', 'is_top'),
        Index('idx_news_article_is_hot', 'is_hot'),
        # 分区索引
        Index('idx_news_article_partition_date', 'partition_date'),
    )
    
    def __repr__(self) -> str:
        return f"<NewsArticle(news_id={self.news_id}, title={self.title[:50]}...)>"


class NewsEvent(BaseFinancialModel, PartitionMixin):
    """
    新闻事件模型
    存储重大金融事件信息
    """
    __tablename__ = "news_event"
    
    # 事件ID
    event_id: Mapped[str] = mapped_column(String(100), primary_key=True, comment="事件ID")
    
    # 事件标题
    title: Mapped[str] = mapped_column(String(500), nullable=False, comment="事件标题")
    
    # 事件描述
    description: Mapped[Optional[str]] = mapped_column(Text, nullable=True, comment="事件描述")
    
    # 事件类型：财报发布, 重组并购, 高管变动, 政策发布, 经济数据等
    event_type: Mapped[str] = mapped_column(String(50), nullable=False, comment="事件类型")
    
    # 事件级别：1-5级，5为最重要
    event_level: Mapped[Integer] = mapped_column(Integer, nullable=False, comment="事件级别")
    
    # 发生时间
    event_time: Mapped[datetime] = mapped_column(DateTime, nullable=False, comment="发生时间")
    
    # 预计时间（对于预告事件）
    expected_time: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True, comment="预计时间")
    
    # 事件状态：预告, 进行中, 已完成, 已取消
    status: Mapped[str] = mapped_column(String(20), nullable=False, comment="事件状态")
    
    # 相关股票代码
    related_stocks: Mapped[Optional[List[str]]] = mapped_column(ARRAY(String), nullable=True, comment="相关股票代码")
    
    # 相关行业代码
    related_industries: Mapped[Optional[List[str]]] = mapped_column(ARRAY(String), nullable=True, comment="相关行业代码")
    
    # 相关指数代码
    related_indices: Mapped[Optional[List[str]]] = mapped_column(ARRAY(String), nullable=True, comment="相关指数代码")
    
    # 影响程度：重大利好, 利好, 中性, 利空, 重大利空
    impact_level: Mapped[Optional[str]] = mapped_column(String(20), nullable=True, comment="影响程度")
    
    # 市场反应
    market_reaction: Mapped[Optional[str]] = mapped_column(Text, nullable=True, comment="市场反应")
    
    # 相关新闻ID列表
    related_news: Mapped[Optional[List[str]]] = mapped_column(ARRAY(String), nullable=True, comment="相关新闻ID")
    
    # 标签
    tags: Mapped[Optional[List[str]]] = mapped_column(ARRAY(String), nullable=True, comment="标签")
    
    # 来源
    source: Mapped[Optional[str]] = mapped_column(String(200), nullable=True, comment="来源")
    
    # 扩展信息
    extra_info: Mapped[Optional[Dict[str, Any]]] = mapped_column(JSONB, nullable=True, comment="扩展信息")
    
    __table_args__ = (
        Index('idx_news_event_title', 'title'),
        Index('idx_news_event_type', 'event_type'),
        Index('idx_news_event_level', 'event_level'),
        Index('idx_news_event_time', 'event_time'),
        Index('idx_news_event_status', 'status'),
        Index('idx_news_event_related_stocks', 'related_stocks', postgresql_using='gin'),
        Index('idx_news_event_related_industries', 'related_industries', postgresql_using='gin'),
        Index('idx_news_event_impact', 'impact_level'),
        Index('idx_news_event_tags', 'tags', postgresql_using='gin'),
        # 分区索引
        Index('idx_news_event_partition_date', 'partition_date'),
    )
    
    def __repr__(self) -> str:
        return f"<NewsEvent(event_id={self.event_id}, title={self.title}, event_type={self.event_type})>"


class NewsResearch(BaseFinancialModel, PartitionMixin):
    """
    研究报告模型
    存储券商研究报告和分析师观点
    """
    __tablename__ = "news_research"
    
    # 报告ID
    report_id: Mapped[str] = mapped_column(String(100), primary_key=True, comment="报告ID")
    
    # 报告标题
    title: Mapped[str] = mapped_column(String(500), nullable=False, comment="报告标题")
    
    # 报告摘要
    summary: Mapped[Optional[str]] = mapped_column(Text, nullable=True, comment="报告摘要")
    
    # 报告内容
    content: Mapped[Optional[str]] = mapped_column(Text, nullable=True, comment="报告内容")
    
    # 报告类型：公司研究, 行业研究, 策略研究, 宏观研究, 固收研究等
    report_type: Mapped[str] = mapped_column(String(50), nullable=False, comment="报告类型")
    
    # 研究机构
    institution: Mapped[str] = mapped_column(String(200), nullable=False, comment="研究机构")
    
    # 分析师
    analyst: Mapped[Optional[str]] = mapped_column(String(200), nullable=True, comment="分析师")
    
    # 发布时间
    publish_time: Mapped[datetime] = mapped_column(DateTime, nullable=False, comment="发布时间")
    
    # 相关股票代码
    stock_code: Mapped[Optional[str]] = mapped_column(String(20), nullable=True, comment="相关股票代码")
    
    # 股票名称
    stock_name: Mapped[Optional[str]] = mapped_column(String(100), nullable=True, comment="股票名称")
    
    # 行业代码
    industry_code: Mapped[Optional[str]] = mapped_column(String(20), nullable=True, comment="行业代码")
    
    # 行业名称
    industry_name: Mapped[Optional[str]] = mapped_column(String(100), nullable=True, comment="行业名称")
    
    # 投资评级：买入, 增持, 中性, 减持, 卖出
    rating: Mapped[Optional[str]] = mapped_column(String(20), nullable=True, comment="投资评级")
    
    # 前次评级
    previous_rating: Mapped[Optional[str]] = mapped_column(String(20), nullable=True, comment="前次评级")
    
    # 目标价格
    target_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="目标价格")
    
    # 前次目标价格
    previous_target_price: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="前次目标价格")
    
    # 预测EPS
    forecast_eps: Mapped[Optional[Dict[str, Any]]] = mapped_column(JSONB, nullable=True, comment="预测EPS")
    
    # 预测营收
    forecast_revenue: Mapped[Optional[Dict[str, Any]]] = mapped_column(JSONB, nullable=True, comment="预测营收")
    
    # 预测净利润
    forecast_profit: Mapped[Optional[Dict[str, Any]]] = mapped_column(JSONB, nullable=True, comment="预测净利润")
    
    # 核心观点
    key_points: Mapped[Optional[List[str]]] = mapped_column(ARRAY(String), nullable=True, comment="核心观点")
    
    # 风险提示
    risk_warning: Mapped[Optional[str]] = mapped_column(Text, nullable=True, comment="风险提示")
    
    # 报告页数
    page_count: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="报告页数")
    
    # 报告链接
    url: Mapped[Optional[str]] = mapped_column(String(1000), nullable=True, comment="报告链接")
    
    # PDF链接
    pdf_url: Mapped[Optional[str]] = mapped_column(String(1000), nullable=True, comment="PDF链接")
    
    # 下载次数
    download_count: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="下载次数")
    
    # 扩展信息
    extra_info: Mapped[Optional[Dict[str, Any]]] = mapped_column(JSONB, nullable=True, comment="扩展信息")
    
    __table_args__ = (
        Index('idx_news_research_title', 'title'),
        Index('idx_news_research_type', 'report_type'),
        Index('idx_news_research_institution', 'institution'),
        Index('idx_news_research_analyst', 'analyst'),
        Index('idx_news_research_publish_time', 'publish_time'),
        Index('idx_news_research_stock', 'stock_code'),
        Index('idx_news_research_industry', 'industry_code'),
        Index('idx_news_research_rating', 'rating'),
        Index('idx_news_research_target_price', 'target_price'),
        # 分区索引
        Index('idx_news_research_partition_date', 'partition_date'),
    )
    
    def __repr__(self) -> str:
        return f"<NewsResearch(report_id={self.report_id}, title={self.title}, institution={self.institution})>"


class NewsAnnouncement(BaseFinancialModel, PartitionMixin):
    """
    公告模型
    存储上市公司公告信息
    """
    __tablename__ = "news_announcement"
    
    # 公告ID
    announcement_id: Mapped[str] = mapped_column(String(100), primary_key=True, comment="公告ID")
    
    # 股票代码
    stock_code: Mapped[str] = mapped_column(String(20), nullable=False, comment="股票代码")
    
    # 股票名称
    stock_name: Mapped[str] = mapped_column(String(100), nullable=False, comment="股票名称")
    
    # 公告标题
    title: Mapped[str] = mapped_column(String(500), nullable=False, comment="公告标题")
    
    # 公告摘要
    summary: Mapped[Optional[str]] = mapped_column(Text, nullable=True, comment="公告摘要")
    
    # 公告类型：定期报告, 临时公告, 澄清公告, 补充公告等
    announcement_type: Mapped[str] = mapped_column(String(50), nullable=False, comment="公告类型")
    
    # 公告分类：财务报告, 重大事项, 股东大会, 董事会决议等
    category: Mapped[str] = mapped_column(String(50), nullable=False, comment="公告分类")
    
    # 发布时间
    publish_time: Mapped[datetime] = mapped_column(DateTime, nullable=False, comment="发布时间")
    
    # 公告日期
    announcement_date: Mapped[date] = mapped_column(Date, nullable=False, comment="公告日期")
    
    # 重要程度：1-5级，5为最重要
    importance_level: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="重要程度")
    
    # 是否重大事项
    is_major_event: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, comment="是否重大事项")
    
    # 影响程度：重大利好, 利好, 中性, 利空, 重大利空
    impact_level: Mapped[Optional[str]] = mapped_column(String(20), nullable=True, comment="影响程度")
    
    # 关键词
    keywords: Mapped[Optional[List[str]]] = mapped_column(ARRAY(String), nullable=True, comment="关键词")
    
    # 涉及金额（万元）
    amount: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 4), nullable=True, comment="涉及金额(万元)")
    
    # 公告链接
    url: Mapped[Optional[str]] = mapped_column(String(1000), nullable=True, comment="公告链接")
    
    # PDF链接
    pdf_url: Mapped[Optional[str]] = mapped_column(String(1000), nullable=True, comment="PDF链接")
    
    # 附件链接
    attachment_urls: Mapped[Optional[List[str]]] = mapped_column(ARRAY(String), nullable=True, comment="附件链接")
    
    # 交易所
    exchange: Mapped[str] = mapped_column(String(20), nullable=False, comment="交易所")
    
    # 扩展信息
    extra_info: Mapped[Optional[Dict[str, Any]]] = mapped_column(JSONB, nullable=True, comment="扩展信息")
    
    __table_args__ = (
        Index('idx_news_announcement_stock', 'stock_code'),
        Index('idx_news_announcement_title', 'title'),
        Index('idx_news_announcement_type', 'announcement_type'),
        Index('idx_news_announcement_category', 'category'),
        Index('idx_news_announcement_publish_time', 'publish_time'),
        Index('idx_news_announcement_date', 'announcement_date'),
        Index('idx_news_announcement_importance', 'importance_level'),
        Index('idx_news_announcement_major', 'is_major_event'),
        Index('idx_news_announcement_impact', 'impact_level'),
        Index('idx_news_announcement_keywords', 'keywords', postgresql_using='gin'),
        Index('idx_news_announcement_exchange', 'exchange'),
        # 分区索引
        Index('idx_news_announcement_partition_date', 'partition_date'),
    )
    
    def __repr__(self) -> str:
        return f"<NewsAnnouncement(announcement_id={self.announcement_id}, stock_code={self.stock_code}, title={self.title})>"


# 导出所有新闻相关模型
__all__ = [
    'NewsArticle',
    'NewsEvent',
    'NewsResearch',
    'NewsAnnouncement',
]